package niumao.minecraft.uhc;

import niumao.minecraft.uhc.indicator.ScoreBoardInfo;
import niumao.minecraft.uhc.listener.Buff;
import niumao.minecraft.uhc.recipes.UHCItem;
import niumao.minecraft.uhc.recipes.recipeGui;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
import org.bukkit.block.Chest;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;

import java.util.*;

public class UHCGame implements Listener {
    private static final Main plugin = Main.getPlugin(Main.class);
    public static World uhcWorld;   //uhc的主世界
    public static World uhcNether;  //uhc的下界
    public static ArrayList<Player> playerList; //进入世界的所有玩家列表
    public static HashMap<UUID, Integer> PlayerKills;   //玩家的击杀数
    public static HashMap<UUID, UUID> lastDamage;   //记录玩家上一次受伤的来源
    public static HashMap<UUID, Location> portalLocation;  //记录玩家传送门的坐标
    public static int timer = 60;   //50分钟时间(35分钟后开启pvp)
    public static boolean isOver = false;  //游戏是否已经结束
    public static boolean canStart = true;  //游戏是否能开始

    /**
     * 线程管理
     */
    //计时器线程
    public static BukkitTask timerTask;
    //开启pvp线程
    public static BukkitTask pvpEnablerTask;
    //战利品线程
    public static BukkitTask lootBoxTask;

    //神器物品
    private static final ArrayList<ItemStack> lootItem = new ArrayList<>();

    //卸载该世界
    public static void unload() {
        if (uhcWorld != null) Bukkit.unloadWorld(uhcWorld, false);
        if (uhcNether != null) Bukkit.unloadWorld(uhcNether, false);
    }

    //游戏开始
    public static void start() {
        UHCItem allItem = new UHCItem();
        lootItem.add(UHCItem.FusionHelmet());
        lootItem.add(UHCItem.FusionChestPlate());
        lootItem.add(UHCItem.FusionLeggings());
        lootItem.add(UHCItem.FusionBoots());
        lootItem.add(allItem.Scythe());
        lootItem.add(allItem.Excalibur());
        lootItem.add(allItem.Perun());
        lootItem.add(allItem.Anduril());
        lootItem.add(allItem.Barbarian());
        lootItem.add(allItem.DragonArmor());
        lootItem.add(allItem.Exodus());
        lootItem.add(allItem.Bloodlust());
        lootItem.add(allItem.Artemis());
        lootItem.add(allItem.Cupid());
        lootItem.add(allItem.Hermes());
        lootItem.add(allItem.Leviathan());
        lootItem.add(allItem.Miner());
        lootItem.add(allItem.Modular());
        lootItem.add(allItem.SevenLeagueBoots());
        lootItem.add(allItem.TarnHelm());
        lootItem.add(allItem.Vidar());
        lootItem.add(allItem.DragonSword());
        lootItem.add(allItem.GoldenHead());
        playerList = new ArrayList<>();
        PlayerKills = new HashMap<>();
        lastDamage = new HashMap<>();
        portalLocation = new HashMap<>();

        //加载uhc世界
        WorldCreator uhcCreator = new WorldCreator("uhc");
        uhcWorld = Bukkit.createWorld(uhcCreator);
        WorldCreator netherCreator = new WorldCreator("world_nether");
        uhcNether = Bukkit.createWorld(netherCreator);

        Random rand = new Random();
        initGame();
        //倒计时5,4,3,2,1
        for (Player player : Bukkit.getOnlinePlayers()) {
            PlayerKills.put(player.getUniqueId(), 0); //每个玩家的初始击杀数
            lastDamage.put(player.getUniqueId(), null);
            portalLocation.put(player.getUniqueId(), null);
            playerList.add(player);
            player.setGameMode(GameMode.SURVIVAL);
            player.setInvulnerable(false);
            for (int i = 5; i > 0; i--)
                countDown(player, i);
        }

        ScoreBoardInfo.Flag = false;  //计分板切换
        //传送到新的世界
        new BukkitRunnable() {
            @Override
            public void run() {
                for (Player player : Bukkit.getOnlinePlayers()) {
                    ScoreBoardInfo.baseTask.cancel();
                    player.teleport(uhcWorld.getHighestBlockAt(1000 - rand.nextInt(2000), 1000 - rand.nextInt(2000)).getLocation());
                    Buff.add(player, (timer - 15) / 2);    //增益buff
                    ScoreBoardInfo.initUHC(player);  //为玩家设置计分板
                }
            }
        }.runTaskLater(plugin, 5 * 20);

        //设置倒计时(每分钟timer减一)
        timerTask = new BukkitRunnable() {
            @Override
            public void run() {
                timer--;
            }

            @Override
            public synchronized void cancel() throws IllegalStateException {
                super.cancel();
            }
        }.runTaskTimer(plugin, 0L, 60 * 20L);

        //开启PVP(倒数15分钟)
        pvpEnablerTask = new BukkitRunnable() {
            @Override
            public void run() {
                uhcWorld.setPVP(true);
                uhcNether.setPVP(true);
                Bukkit.broadcastMessage("§aPVP已经开启");
            }

            @Override
            public synchronized void cancel() throws IllegalStateException {
                super.cancel();
            }
        }.runTaskLater(plugin, 20 * 60 * 20L);

        //战利品
        lootBoxTask = new BukkitRunnable() {
            @Override
            public void run() {
                int size = (int) uhcWorld.getWorldBorder().getSize() / 2 - 100;
                int x = (size - rand.nextInt(size * 2));
                int z = (size - rand.nextInt(size * 2));
                int y = uhcWorld.getHighestBlockYAt(x, z);
                Location chestLoc = new Location(uhcWorld, x, y, z);
                for (Player player : Bukkit.getOnlinePlayers()) {
                    if (player.getWorld().getName().equalsIgnoreCase("world")) return;
                    int distance = (int) player.getLocation().distance(chestLoc);
                    player.sendMessage("神器箱将在1分钟后生成" + ChatColor.GREEN + "[" + x + ", " + "~, " + z + "]"
                            + ChatColor.YELLOW + "距离" + distance + "格");
                }
                spawnLootChest(chestLoc);   //1分钟后生成战利品
            }

            @Override
            public synchronized void cancel() throws IllegalStateException {
                super.cancel();
            }
        }.runTaskTimer(plugin, 0L, (rand.nextInt(5) + 5) * 60 * 20);
    }

    //游戏结束
    public static void over(Player lastStandPlayer) {
        isOver = true;
        canStart = true;
        String winner = null;
        if (lastStandPlayer != null) {
            lastStandPlayer.setInvulnerable(true);
            winner = lastStandPlayer.getDisplayName();
        }

        String st;
        String nd;
        String rd;
        int stK;
        int ndK;
        int rdK;

        ArrayList<String> names = new ArrayList<>();
        ArrayList<Integer> kills = new ArrayList<>();

        for (Player player : playerList) {
            names.add(player.getDisplayName());
            kills.add(PlayerKills.get(player.getUniqueId()));
        }

        if (names.size() == 1 && kills.size() == 1) {
            names.add(null);
            kills.add(0);
            names.add(null);
            kills.add(0);
        }

        if (names.size() == 2 && kills.size() == 2) {
            names.add(null);
            kills.add(0);
        }

        int max = kills.get(0);
        int flag = 0;
        for (int i = 0; i < kills.size(); i++) {
            if (max <= kills.get(i)) {
                max = kills.get(i);
                flag = i;
            }
        }
        stK = max;
        st = names.get(flag);
        kills.remove(flag);
        names.remove(flag);

        max = kills.get(0);
        for (int i = 0; i < kills.size(); i++) {
            if (max <= kills.get(i)) {
                max = kills.get(i);
                flag = i;
            }
        }
        ndK = max;
        nd = names.get(flag);
        kills.remove(flag);
        names.remove(flag);

        max = kills.get(0);
        for (int i = 0; i < kills.size(); i++) {
            if (max <= kills.get(i)) {
                max = kills.get(i);
                flag = i;
            }
        }
        rdK = max;
        rd = names.get(flag);
        kills.remove(flag);
        names.remove(flag);

        Bukkit.broadcastMessage(ChatColor.GREEN + "§l---------------------------------------------");
        Bukkit.broadcastMessage("                    " + getStr("UHC"));
        Bukkit.broadcastMessage("");
        Bukkit.broadcastMessage("                          " + getStr("Winner") + ChatColor.GRAY + " - " + ChatColor.WHITE + winner);
        Bukkit.broadcastMessage("");
        Bukkit.broadcastMessage(ChatColor.YELLOW + "                      " + getStr("stKiller") + ChatColor.GRAY + " - " + ChatColor.WHITE + st + ChatColor.GRAY + " - " + stK + getStr("Kills"));
        Bukkit.broadcastMessage(ChatColor.YELLOW + "                      " + getStr("ndKiller") + ChatColor.GRAY + " - " + ChatColor.WHITE + nd + ChatColor.GRAY + " - " + ndK + getStr("Kills"));
        Bukkit.broadcastMessage(ChatColor.YELLOW + "                      " + getStr("rdKiller") + ChatColor.GRAY + " - " + ChatColor.WHITE + rd + ChatColor.GRAY + " - " + rdK + getStr("Kills"));
        Bukkit.broadcastMessage("");
        Bukkit.broadcastMessage(ChatColor.GREEN + "§l---------------------------------------------");

        //tp所有玩家返回主大厅(游戏结束10秒后)
        new BukkitRunnable() {
            @Override
            public void run() {
                ScoreBoardInfo.Flag = true;
                if (ScoreBoardInfo.uhcTask != null) ScoreBoardInfo.uhcTask.cancel();  //将原来的计分板取消
                List<Player> players = uhcWorld.getPlayers();
                players.addAll(uhcNether.getPlayers());
                for (Player player : players) {
                    ScoreBoardInfo.initBase(player);
                    //清楚玩家身上的物品
                    for (int i = 0; i <= 40; i++) {
                        ItemStack item = player.getInventory().getItem(i);
                        if (item == null) continue;
                        player.getInventory().setItem(i, null);
                    }
                    player.teleport(Objects.requireNonNull(Bukkit.getWorld("world")).getSpawnLocation());
                    player.getInventory().setItem(0, recipeGui.RecipeBook());
                }

                //结束所有的线程
                timerTask.cancel();
                pvpEnablerTask.cancel();
                lootBoxTask.cancel();
            }
        }.runTaskLater(plugin, 10 * 20L);


        //卸载世界,且不保存,并重新加载世界
        new BukkitRunnable() {
            @Override
            public void run() {
                Bukkit.unloadWorld(uhcWorld, false);
                Bukkit.unloadWorld(uhcNether, false);
            }
        }.runTaskLater(plugin, 12 * 20L);
    }

    //开始时的初始化方法
    private static void initGame() {
        canStart = false;
        isOver = false;

        //各项的初始化
        playerList = new ArrayList<>();
        PlayerKills = new HashMap<>();
        lastDamage = new HashMap<>();
        portalLocation = new HashMap<>();
        timer = 60; //时间60分钟

        //uhc世界的基本设定
        WorldBorder worldBorder = uhcWorld.getWorldBorder();
        worldBorder.setCenter(0, 0);
        worldBorder.setSize(2000);
        worldBorder.setSize(10, timer * 60L);   //此处的v代表边界大小(|x+z|),l代表时间(单位:秒)
        worldBorder.setDamageAmount(1);
        worldBorder.setDamageBuffer(3);
        uhcWorld.setDifficulty(Difficulty.HARD);
        uhcWorld.setGameRule(GameRule.NATURAL_REGENERATION, false);
        uhcWorld.setGameRule(GameRule.DO_MOB_SPAWNING, true);
        uhcWorld.setGameRule(GameRule.SPECTATORS_GENERATE_CHUNKS, false);
        uhcWorld.setTime(1000L);
        uhcWorld.setPVP(false);

        //uhc下界的基本设定
        WorldBorder netherBorder = uhcNether.getWorldBorder();
        netherBorder.setCenter(0, 0);
        netherBorder.setSize(2000);
        netherBorder.setSize(10, timer * 60);   //此处的v代表边界大小(|x+z|),l代表时间(单位:秒)
        netherBorder.setDamageAmount(1);
        netherBorder.setDamageBuffer(0);
        uhcNether.setDifficulty(Difficulty.HARD);
        uhcNether.setGameRule(GameRule.NATURAL_REGENERATION, false);
        uhcNether.setGameRule(GameRule.DO_MOB_SPAWNING, true);
        uhcNether.setGameRule(GameRule.SPECTATORS_GENERATE_CHUNKS, false);
        uhcNether.setPVP(false);

    }

    //获取目前游戏所存活的玩家
    public static int getSurvivals() {
        List<Player> players = uhcWorld.getPlayers();
        players.addAll(uhcNether.getPlayers());
        int survivals = players.size();
        for (Player player : players) {
            if (player.getGameMode() != GameMode.SURVIVAL)
                survivals--;
        }
        return survivals;
    }

    //获取存活到最后的玩家
    private static Player getLastSurvival(World world) {
        List<Player> players = world.getPlayers();
        for (Player player : players) {
            if (player.getGameMode() == GameMode.SURVIVAL)
                return player;
        }
        return null;
    }

    private static String getStr(String name) {
        return plugin.getConfig().getString("GameInfo." + Main.getLang() + "." + name);
    }

    //生成战利品
    private static void spawnLootChest(Location chestLoc) {
        new BukkitRunnable() {
            @Override
            public void run() {
                if (UHCGame.isOver) return;
                chestLoc.getBlock().setType(Material.CHEST);
                Chest chest = (Chest) chestLoc.getBlock().getState();
                Inventory inv = chest.getBlockInventory();
                Random rand = new Random();
                //添加一个神器
                inv.addItem(lootItem.get(rand.nextInt(lootItem.size())));
                //添加5~17个金锭
                inv.addItem(new ItemStack(Material.GOLD_INGOT, 5 + rand.nextInt(12)));
                //百分之20几率添加1~5个钻石
                if (rand.nextInt(100) < 20) inv.addItem(new ItemStack(Material.DIAMOND, 1 + rand.nextInt(4)));
                Bukkit.broadcastMessage(ChatColor.GREEN + "神器箱已成功生成!");
            }
        }.runTaskLater(plugin, 60 * 20L);
    }

    //倒计时方法
    private static void countDown(Player player, int i) {
        new BukkitRunnable() {
            @Override
            public void run() {
                player.sendTitle("" + i, null, 0, 20, 0);
                player.playSound(player.getLocation(), Sound.BLOCK_TRIPWIRE_ATTACH, 1, 1);
            }
        }.runTaskLater(plugin, (5 - i) * 20L);
    }

    /**
     * 以下为事件
     */

    //自定义玩家死亡事件
    @EventHandler
    public void onPlayerDeath(EntityDamageEvent event) {
        if (!(event.getEntity() instanceof Player)) return;
        Player player = (Player) event.getEntity();
        if (!player.getWorld().getName().equalsIgnoreCase("uhc")
                ||!player.getWorld().getName().equalsIgnoreCase("world_nether")) return;
        if (player.getLastDamageCause() == null) return;

        //玩家死亡
        if (event.getFinalDamage() >= player.getHealth()) {
            event.setCancelled(true);

            //打雷特效
            player.getWorld().strikeLightningEffect(player.getLocation());
            player.setHealth(Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue());
            player.setGameMode(GameMode.SPECTATOR);

            //播送死亡信息
            plugin.getServer().broadcastMessage(player.getName() + "已经死亡!");

            //掉落头颅,金锭与背包内的物品
            World world = player.getWorld();
            world.dropItem(player.getLocation(), new ItemStack(Material.PLAYER_HEAD));
            world.dropItem(player.getLocation(), new ItemStack(Material.GOLD_INGOT, 10));
            for (int i = 0; i <= 40; i++) {
                ItemStack item = player.getInventory().getItem(i);
                if (item == null) continue;
                world.dropItem(player.getLocation(), item);
                player.getInventory().setItem(i, null);
            }

            //击杀者的击杀数加一
            UUID uuid = lastDamage.get(player.getUniqueId());
            if (uuid != null) {
                PlayerKills.putIfAbsent(uuid, 0);
                PlayerKills.put(uuid, PlayerKills.get(uuid) + 1);
            }

            //游戏结束判断
            if (isOver) return;
            new BukkitRunnable() {
                @Override
                public void run() {
                    if (getSurvivals() <= 1) over(getLastSurvival(world));
                }
            }.runTaskLater(plugin, 20L);
        }
    }

    //记录玩家上一次被攻击的攻击者
    @EventHandler
    public void recordLastDamage(EntityDamageByEntityEvent event) {
        Player player= (Player) event.getDamager();
        if (!player.getWorld().getName().equalsIgnoreCase("uhc")
                ||!player.getWorld().getName().equalsIgnoreCase("world_nether")) return;
        if (event.getEntity() instanceof Player) {
            //玩家射箭判断
            if (event.getDamager().getType().equals(EntityType.ARROW)) {
                Arrow arrow = (Arrow) event.getDamager();
                if (arrow.getShooter() instanceof Player)
                    lastDamage.put(event.getEntity().getUniqueId(), ((Player) arrow.getShooter()).getUniqueId());
                return;
            }
            //玩家普通击打
            if (event.getEntity() instanceof Player)
                lastDamage.put(event.getEntity().getUniqueId(), event.getDamager().getUniqueId());
        }
    }

    //玩家进入新旧的世界的基本设置,加上地狱世界的设置
    @EventHandler
    public void onPlayerChangeWorld(PlayerChangedWorldEvent event) {
        Player player = event.getPlayer();
        new BukkitRunnable() {
            @Override
            public void run() {
                if (player.getWorld().getName().equalsIgnoreCase("world")) {
                    player.setGameMode(GameMode.ADVENTURE);
                    player.setInvulnerable(true);
                    player.setFoodLevel(20);
                    player.setExp(0);
                    player.setHealth(Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue());
                    for (PotionEffect effect : player.getActivePotionEffects())
                        player.removePotionEffect(effect.getType());
                    ScoreBoardInfo.initBase(player);
                }
            }
        }.runTaskLater(plugin, 10L);
    }

    //玩家从地狱返回uhc世界
    @EventHandler
    public void onPlayerEnterPortal(PlayerPortalEvent event) {
        Player player = event.getPlayer();
        //保存传送前的位置
        if (player.getWorld().getName().equalsIgnoreCase("uhc")) {
            portalLocation.put(player.getUniqueId(), player.getLocation());
            return;
        }
        if (player.getWorld().getName().equalsIgnoreCase("world_nether")) {
            if (portalLocation.get(player.getUniqueId()) == null) {
                event.setCancelled(true);
                return;
            }
            event.setTo(portalLocation.get(player.getUniqueId()));
            return;
        }
        if (player.getWorld().getName().equalsIgnoreCase("world"))
            event.setCancelled(true);
    }
}
